home *** CD-ROM | disk | FTP | other *** search
/ Programming Sound Cards / Programming Sound Cards.iso / sound_56 / dmastep2.asm < prev    next >
Encoding:
Assembly Source File  |  1995-01-01  |  15.9 KB  |  414 lines

  1. ;══════════════════════════════════════════════════════════════════════════════
  2. ; Play 8bit DMA mode for SoundBlaster v1.00
  3. ;   André Baresel
  4. ;──────────────────────────────────────────────────────────────────────────────
  5. ; STATUS: DOES WORK ON SB16/SBPRO2/SB2.0, TESTPHASE ON SB1.0
  6. ;──────────────────────────────────────────────────────────────────────────────
  7. ; Requirements: 80286, SoundBlaster (see BASEADDR,DMA channel,IRQ number)
  8. ; Resolutions : 8-bit / 4..23khz (no highspeed - but on SB16 4..44kHz)
  9. ; Parameters  : none
  10. ; Notes:
  11. ;  ■ To creat a 8 bit mono unsigned file do :   "VOC2RAW TEST1.VOC /I"
  12. ;
  13. ; ■ DSP command 14h  ... play 8bit mono no autoinit
  14. ; ■ DSP command 40h  ... set sample rate
  15. ; ■ DSP command D1h  ... Enable Speaker
  16. ; ■ DSP command D3h  ... Disable Speaker
  17. ; ■ DSP command D0h  ... Halt 8 bit DMA transfer
  18. ; ■ DSP command D4h  ... continue 8 bit DMA transfer
  19. ;
  20.  
  21. .MODEL SMALL
  22. .286
  23.  
  24. ; CONSTANTS ───────────────────────────────────────────────────────────────────
  25.  
  26. ; SoundBlaster SETUP
  27. BASEADDR           EQU 0220h       ;SoundBlaster base address
  28. IRQ7               EQU 15          ;SoundBlaster IRQ
  29. DMAchannel         EQU 1           ;SoundBlaster DMA channel
  30.  
  31. ; PIC MASKS FOR MASK/DEMASK IRQ
  32. PICANDMASK         EQU 01111111b   ;'AND' PIC mask for clear IRQ7
  33. PICORMASK          EQU 10000000b   ;'OR' PIC mask for set IRQ7
  34.  
  35. ; DMA CONTROLLER REGISTERS :
  36. WRITEMASK          EQU 00ah         ;WRITE MASK REGISTER
  37. WRITEMODE          EQU 00bh         ;WRITE MODE REGISTER
  38. CLEARFLIPFLOP      EQU 00ch
  39. PAGE_CHN           EQU 083h         ;PAGE REGISTER FOR DMAchannel 1
  40. BASE_CHN           EQU 002h         ;BASEADDRESS REGISTER DMA 1
  41. COUNT_CHN          EQU 003h         ;COUNT REGISTER DMAchannel 1
  42.  
  43. ; SAMPLERATE : (if you change it pay attention to maximum samplerate)
  44. TIMECONST          EQU 165          ; = 10989 Hz (256-1000000/11000)
  45.  
  46. ; DMA WRITE MODE
  47. WANTEDMODE         EQU 01001000b    ; singlemode, nonautoinit, readmode
  48.  
  49. ;──────────────────────────────────────────────────────────────────────────────
  50. ; MACRO DEFINITIONs
  51. ;──────────────────────────────────────────────────────────────────────────────
  52. STARTUP                 MACRO
  53. ; MASM 5.x COMPATIBILITY
  54. __start:                mov     ax,DGROUP
  55.                         mov     ds,ax
  56.                         mov     bx,ss
  57.                         sub     bx,ax
  58.                         shl     bx,004h
  59.                         mov     ss,ax
  60.                         add     sp,bx
  61. ENDM
  62.  
  63. WAITWRITE               MACRO
  64. LOCAL                   loopWait,endloop
  65. ;          Arguments : DX = Status port (BASEADDR+0Ch)
  66. ;          Returns   : n/a
  67. ;          Destroys  : AL
  68.  
  69.                         push    cx
  70.                         xor     cx,cx           ; need that for slow SBs !
  71. loopWait:               dec     cx
  72.                         jz      endloop
  73.                         in      al,dx           ; AL = WRITE COMMAND STATUS
  74.                         or      al,al
  75.                         js      loopWait        ; Jump if bit7=1 - writing not allowed
  76. endloop:                pop     cx
  77. ENDM
  78.  
  79. WAITREAD                MACRO
  80. LOCAL                   loopWait,endloop
  81. ;          Arguments : DX = Status port   (normaly BASEADDR+0Eh)
  82. ;          Returns   : n/a
  83. ;          Destroys  : AL
  84.  
  85.                         push    cx
  86.                         xor     cx,cx           ; need that for slow SBs !
  87. loopWait:               dec     cx
  88.                         jz      endloop
  89.                         in      al,dx           ; AL = DATA AVAILABLE STATUS
  90.                         or      al,al
  91.                         jns     loopWait        ; Jump if bit7=0 - no data available
  92. endloop:                pop     cx
  93. ENDM
  94.  
  95. RESET_DSP               MACRO
  96. local                   SBthere
  97. ;          Arguments : n/a
  98. ;          Returns   : n/a
  99. ;          Destroys  : DX,AL
  100.  
  101.                         mov      dx,BASEADDR+06h
  102.                         mov      al,1
  103.                         out      dx,al          ; start DSP reset
  104.  
  105.                         in       al,dx
  106.                         in       al,dx
  107.                         in       al,dx
  108.                         in       al,dx          ; wait 3 µsec
  109.  
  110.                         xor      al,al
  111.                         out      dx,al          ; end DSP Reset
  112.  
  113.                         add      dx,08h         ; dx = DSP DATA AVAILABLE
  114.                         WAITREAD
  115.                         sub      dx,4           ; dx = DSP Read Data
  116.                         in       al,dx
  117.                         cmp      al,0aah        ; if there is a SB then it returns 0AAh
  118.                         je       SBthere
  119.                         jmp      RESET_ERROR    ; No SB - exit program
  120. SBthere:
  121. ENDM
  122. ;─── End of Macrodefinitions ──────────────────────────────────────────────────
  123.  
  124. .STACK 100h
  125.  
  126. .DATA
  127. ;──────────────────────────────────────────────────────────────────────────────
  128. ; TWO COPIES FOR PAGE OVERRIDE REASONS :
  129.  
  130. SAMPLEBUFFER LABEL BYTE
  131.     INCLUDE TEST1.INC        ; FIRST COPY OF SAMPLE SOUND
  132. SAMPLEBUFFEREND LABEL BYTE
  133.     INCLUDE TEST1.INC        ; SECOND COPY OF SAMPLE SOUND
  134.  
  135.     ready               db 0
  136.  
  137.     information         db 13,10,'DMASTEP2.EXE - play/pause/restart a 8bit mono sample'
  138.                         db 13,10,'               (use DMA no autoinit)'
  139.                         db 13,10,' Keys :'
  140.                         db 13,10,' R ........... restart sample'
  141.                         db 13,10,' P ........... pause playing and continue after this with any key'
  142.                         db 13,10,' any other ..... quit program','$'
  143.  
  144.     sberror             db 13,10,'No SoundBlaster at this BASEADDR ! PROGRAM HALTED.','$'
  145.  
  146.     OLDInterruptSEG     dw ?
  147.     OLDInterruptOFS     dw ?
  148.  
  149.     SAMPLEBUFFERLENGTH = offset SAMPLEBUFFEREND - offset SAMPLEBUFFER
  150. ;──────────────────────────────────────────────────────────────────────────────
  151. .CODE
  152.  STARTUP
  153.  
  154.            RESET_DSP
  155.  
  156.            ; WRITE INFORMATION TO SCREEN :
  157.            mov     dx,offset information
  158.            mov     ah,9                        ; write program information to screen
  159.            int     21h
  160.  
  161.            ; ENABLE SB SPEAKERS (for all SBs <SB16)
  162.            mov     dx,BASEADDR+00Ch            ;DX = DSP Write Data or Command
  163.            WAITWRITE
  164.            mov     al,0D1h                     ; AL = Enable speaker
  165.            out     dx,al                       ; Output: DSP Write Data or Command
  166.  
  167.            ; SETUP IRQ :
  168.            xor     ax,ax
  169.            mov     es,ax                       ; es to page 0 (Interrupt table)
  170.            mov     si,IRQ7*4                   ; si = position in interrupt table
  171.  
  172.            ; DISABLE IRQ
  173.            in      al,021h
  174.            and     al,PICANDMASK               ; SET MASK REGISTER BIT TO DISABLE INTERRUPT
  175.            out     021h,al
  176.  
  177.            ; CHANGE POINTER IN INTERRUPT TABLE
  178.            mov     ax,es:[si]
  179.            mov     [OLDInterruptOFS],ax        ; save offset of old interupt vector for restoring
  180.            mov     ax,OFFSET OWN_IRQ
  181.            mov     es:[si],ax                  ; set offset of new interrupt routine
  182.            mov     ax,es:[si+2]
  183.            mov     [OLDInterruptSEG],ax        ; save segment of old interupt vector for restoring
  184.            mov     ax,cs
  185.            mov     es:[si+2],ax                ; set segment of new interrupt routine
  186.  
  187.            ; CHANGE PIC MASK :
  188.            in      al,021h
  189.            and     al,PICANDMASK   ; CLEAR MASK REGISTER BIT TO ENABLE INTERRUPT
  190.            out     021h,al
  191.  
  192. ;──────────────────────────────────────────────────────────────────────────────
  193. ; MAIN LOOP - here we restart the sample later
  194.  
  195. start:
  196.                 mov     si,offset samplebuffer
  197.                 mov     cx,SAMPLEBUFFERLENGTH-1
  198.  
  199.                 mov     [ready],0
  200.  
  201. ;──────────────────────────────────────────────────────────────────────────────
  202. ; calculate page and offset for DMAcontroller :
  203. ;
  204. ; segment*16+offset - 20bit memory location -> upper 4 bits  = page
  205. ;                                              lower 16 bits = offset
  206. ;──────────────────────────────────────────────────────────────────────────────
  207.            mov     si,offset samplebuffer
  208.            mov     cx,SAMPLEBUFFERLENGTH-1
  209.  
  210.            mov     ax,ds
  211.            rol     ax,4                ; * 16 - higher 4 bits in al
  212.            mov     bl,al
  213.            and     bl,00fh             ; BL - higher 4 bits
  214.            and     al,0f0h             ; clear higher 4bits in AL
  215.            add     si,ax               ; SI = offset
  216.            adc     bl,0                ; BL = page
  217. ;──────────────────────────────────────────────────────────────────────────────
  218. ; check for DMApage override :
  219. ; ... problem: DMA controller separates memory into 64KB pages, you can only
  220. ; transfer data is placed in one page - no page overrides are allowed
  221. ;──────────────────────────────────────────────────────────────────────────────
  222. ; To solve that :
  223. ; creat a DMA buffer with double size you want - if the first part is placed
  224. ; on a page border the second part is for sure not
  225. ;──────────────────────────────────────────────────────────────────────────────
  226.            neg     si          ; si = 65536 - si   (bytes left to DMA page border)
  227.            cmp     si,cx       ; if si (bytes left to border) > cx (bytes to play)
  228.            ja      nooverride  ; then there's no page override
  229.  
  230.            ; WE HAVE TO USE SECOND PART
  231.            neg     si          ; si = offset of first part
  232.            add     si,cx       ; si = si + length of one part
  233.            inc     si          ; si=si+1 - start of second part
  234.            inc     bl          ; second part is then on the next page
  235.            neg     si          ; look at the next command ;)
  236.                                ; (that is better than a jump ?)
  237. nooverride:
  238.            neg     si
  239.  
  240. ;──────────────────────────────────────────────────────────────────────────────
  241. ; Setup DMA-controller :
  242. ;
  243. ; 1st  MASK DMA CHANNEL
  244. ;
  245.            mov     al,DMAchannel
  246.            add     al,4
  247.            out     WRITEMASK,al
  248. ;──────────────────────────────────────────────────────────────────────────────
  249. ; 2nd  CLEAR FLIPFLOP
  250. ;
  251.            out     CLEARFLIPFLOP,al
  252. ;──────────────────────────────────────────────────────────────────────────────
  253. ; 3rd  WRITE TRANSFER MODE
  254. ;
  255.            mov     al,WANTEDMODE
  256.            add     al,DMAchannel
  257.            out     WRITEMODE,al
  258. ;──────────────────────────────────────────────────────────────────────────────
  259. ; 4th  WRITE PAGE NUMBER
  260. ;
  261.            mov     al,bl
  262.            out     PAGE_CHN,al
  263. ;──────────────────────────────────────────────────────────────────────────────
  264. ; 5th  WRITE BASEADDRESS
  265. ;
  266.            mov     ax,si
  267.            out     BASE_CHN,al
  268.            mov     al,ah
  269.            out     BASE_CHN,al
  270. ;──────────────────────────────────────────────────────────────────────────────
  271. ; 6th  WRITE SAMPLELENGTH-1
  272. ;
  273.            mov     al,cl
  274.            out     COUNT_CHN,al
  275.            mov     al,ch
  276.            out     COUNT_CHN,al
  277. ;──────────────────────────────────────────────────────────────────────────────
  278. ; 7th  DEMASK CHANNEL
  279. ;
  280.            mov     al,DMAchannel
  281.            out     WRITEMASK,al
  282.  
  283. ;──────────────────────────────────────────────────────────────────────────────
  284. ; Setup SoundBlaster :
  285. ;
  286. ; 1st  SET TIMECONSTANTE
  287. ;
  288.            mov     dx,BASEADDR+00Ch            ;DX = DSP Write Data or Command
  289.            WAITWRITE
  290.            mov     al,040h                     ;AL = Set timeconstant
  291.            out     dx,al
  292.            WAITWRITE
  293.            mov     al,TIMECONST
  294.            out     dx,al
  295.  
  296. ;──────────────────────────────────────────────────────────────────────────────
  297. ; 2nd  set DMAplay 8bit mono nonautoinit (DSPcommand-014h)
  298. ;
  299.            WAITWRITE
  300.            mov     al,014h                     ;AL = DMA DAC 8bit
  301.            out     dx,al
  302.            mov     cx,SAMPLEBUFFERLENGTH-1
  303.            WAITWRITE
  304.            mov     al,cl                       ;AL = LOWER PART SAMPLELENGTH
  305.            out     dx,al
  306.            WAITWRITE
  307.            mov     al,ch                       ;AL = HIGHER PART SAMPLELENGTH
  308.            out     dx,al
  309.  
  310. ; TRANSFER STARTS ....... NOW ..... :)
  311.  
  312. waitloop:
  313.            mov     ah,01                       ;AH = Check for character function
  314.            int     016h                        ;   Interrupt: Keyboard
  315.            jz      waitloop                    ; wait for any key
  316.  
  317.            xor     ah,ah                       ;Read character, flush keypress
  318.            int     016h                        ;   Interrupt: Keyboard
  319.            cmp     al,'r'
  320.            jne     norestart
  321.  
  322.            ; HERE TERMINATE CURRENT SAMPLE :
  323.            mov     dx,BASEADDR+00Ch            ;DX = DSP Write Data or Command
  324.            WAITWRITE
  325.            mov     al,0D0h                     ;AL = Halt DMA Operation, 8-bit
  326.            out     dx,al                       ;   Output: DSP Write Data or Command
  327.            WAITWRITE
  328.            mov     al,0DAh                     ;AL = terminate 8-bit DMA Operation
  329.            out     dx,al                       ;   Output: DSP Write Data or Command
  330.            WAITWRITE
  331.            mov     al,0D0h                     ;AL = Halt DMA Operation, 8-bit
  332.            out     dx,al                       ;   Output: DSP Write Data or Command
  333.  
  334.            jmp        start
  335. norestart:
  336.            cmp     al,'p'
  337.            jne     exit
  338.            cmp     [ready],1                   ; sample still playing ?
  339.            je      waitloop                    ; not ! return to waitloop
  340.  
  341.            ; NOW HALT PLAYING :
  342.            mov     dx,BASEADDR+0Ch
  343.            WAITWRITE
  344.            mov     al,0d0h                     ; AL = DSP halt 8bit DMA
  345.            out     dx,al
  346.  
  347.            ; WAIT FOR ANY KEY :
  348.            xor     ah,ah                       ;Read character, flush keypress
  349.            int     016h                        ;   Interrupt: Keyboard
  350.  
  351.            ; CONTINUE PLAYING :
  352.            mov     dx,BASEADDR+0Ch
  353.            WAITWRITE
  354.            mov     al,0d4h                     ; AL = DSP continue 8bit DMA
  355.            out     dx,al
  356.            jmp     waitloop
  357.  
  358. exit:
  359.            ; FIRST TERMINATE DMA TRANSFER :
  360.            cmp     [ready],1
  361.            je      allready_done               ; nothin to do allready done
  362.  
  363.            ; RESET SOUNDBLASTER
  364.            RESET_DSP
  365. allready_done:
  366.  
  367.            ; RESTORE PIC MASK
  368.            in      al,021h
  369.            or      al,PICORMASK                ;<-- SET REGISTER MASK BITS TO DISABLE
  370.            out     021h,al
  371.  
  372.            ; RESTORE IRQ :
  373.            xor     ax,ax
  374.            mov     es,ax                       ; es to page 0 (Interrupt table)
  375.            mov     si,IRQ7*4
  376.            mov     ax,[OLDInterruptOFS]
  377.            mov     es:[si],ax                  ; set old interrupt routine
  378.            mov     ax,[OLDInterruptSEG]
  379.            mov     es:[si+2],ax
  380.  
  381.            ; TERMINATE EXE:
  382. return2dos:
  383.            mov     ax,04c00h
  384.            int     21h          ; bye bye
  385.  
  386. ; display information if Soundblaster is not on this baseaddress
  387. RESET_ERROR:
  388.            mov     dx,offset sberror
  389.            mov     ah,9
  390.            int     21h                         ; text output
  391.            jmp     return2dos
  392.  
  393. ;──────────────────────────────────────────────────────────────────────────────
  394. ; Our own IRQ for detecting end of playing
  395. ; It's generated by the SoundBlaster hardware
  396. ;──────────────────────────────────────────────────────────────────────────────
  397. OWN_IRQ:
  398.            push    ax
  399.            push    dx
  400.            push    ds
  401.            mov     dx,BASEADDR+00Eh            ;DX = DSP DATA AVAILABLE (IRQ ACKNOWLEDGE)
  402.            in      al,dx
  403.            mov     ax,@DATA
  404.            mov     ds,ax
  405.            mov     [READY],1                   ; Sample done ...
  406.            mov     al,020h
  407.            out     020h,al                     ;ACKNOWLEDGE HARDWARE INTERRUPT - PIC1
  408.            pop     ds
  409.            pop     dx
  410.            pop     ax
  411.            IRET
  412.  
  413. END     __start
  414.